from numpy import *
import matplotlib.pyplot as plt

def classify0(inx, dataSet, labels, k):
    '''
    - parameters:
      - inx: numpy array.input value
      - dataSet: numpy array.existing data set
      - labels: numpy array.classify data set
      - k: int.the foremost k values participate in the calculation
    - return the label that the most frequently appeared
    '''
    dataSetSize = dataSet.shape[0]  # the number of input data
    diffMat = tile(inx, (dataSetSize, 1)) - dataSet
    # expand inx by  row direction,make the shape like dataSet
    sqDiffMat = diffMat ** 2
    sqDistances = sqDiffMat.sum(axis=1)  # axis=1 calculate by every row
    distances = sqDistances ** 0.5
    sortedDistances = distances.argsort()
    # sort matrix In ascending order (default quikesort) return index list Corresponde to Original array

    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistances[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
        # build a dict key by get(element,0)  count appeared the numbers of every class
    sortedClassCount = sorted(classCount.items(), key=lambda x:x[1], reverse=True)
        # itemgetter(1) obey by the second elemment // item() return tuple type contain key and value
    return sortedClassCount[0][0]


def file2matrix(filename):
    f = open(filename)
    rldata = f.readlines()
    numline = len(rldata)
    returnMat = zeros((numline, 3))  # Apply for space in advance
    labels = []
    index = 0
    for line in rldata:
        line = line.strip()
        # strip() 方法用于移除字符串头尾指定的字符（默认为空格或换行符）或字符序列
        listFromLine = line.split('\t')
        # return a list of the words in the string
        returnMat[index, :] = listFromLine[0:3]
        labels.append(int(listFromLine[-1]))
        index += 1
    return returnMat, labels


def nxnorm(dataSet):
    minval = dataSet.min(0)
    # Return the minimum along a given axis.
    maxval = dataSet.max(0)
    ranges = maxval - minval
    normSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normSet = (dataSet-tile(minval, (m, 1)))/tile(ranges, (m, 1))
    return normSet, ranges, minval


def dataingClassTest(file,k):
    horatio = 0.1
    datas, labels = file2matrix(file)
    normData, ranges, minval = nxnorm(datas)
    m = normData.shape[0]
    numtest = int(m * horatio)
    errnum = 0
    for i in range(numtest):
        classifierResult = classify0(normData[i, :], normData[numtest:m, :], labels[numtest:m], k)
        print('the classifier cameback with: %d,the real answer is: %d' % (classifierResult, labels[i]))
        if classifierResult != labels[i]:
            errnum += 1
    print('the total error rate is: %f' % (errnum / float(numtest)))


def classifyPerson(filename, k):
    resultList = ['not at all', 'in small does', 'in large does']
    ffMiles = float(input('frequent flier miles earned per year?'))
    percentTats = float(input('percentage of time spent playing video games?'))
    iceCream = float(input('liters of ice cream consumed per year?'))
    datas, labels = file2matrix(filename)
    normData, ranges, minval = nxnorm(datas)
    inx = array([ffMiles, percentTats, iceCream])
    inx = (inx - minval) / ranges
    classifierResult = classify0(inx, normData, labels, k)
    print('You will probably like this person:', resultList[classifierResult - 1])


def img2vector(filename):
    returnVect = zeros((1, 1024))
    fr = open(filename)
    for i in range(32):
        linestr = fr.readline()
        for j in range(32):
            returnVect[0, 32 * i + j] = int(linestr[j])
    return returnVect


def writingDigitalClassifier(path1, path2):
    import os
    hwlabels = []
    trainingflist = os.listdir(path1)
    m = len(trainingflist)
    trainingMat = zeros((m, 1024))
    for i in range(m):
        filenameStr = trainingflist[i]
        fileStr = filenameStr.split('.')[0]
        classnumStr = int(fileStr.split('_')[0])
        hwlabels.append(classnumStr)
        trainingMat[i, :] = img2vector(path1+'/%s' % filenameStr)
    testflist = os.listdir(path2)
    errnum = 0.0
    mtest = len(testflist)
    for i in range(mtest):
        filenameStr = testflist[i]
        fileStr = filenameStr.split('_')[0]
        classnumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector(path2+'%s' % filenameStr)
        classifierResult  =  classify0(vectorUnderTest,trainingMat,hwlabels,3)
        print('the classifier came back with: %d, the real answer is: %d' % (classifierResult,classnumStr))
        if classifierResult != classnumStr:
            errnum += 1.0
        print('the total number of errors is: %d' % errnum)
        print('the total error rate is : %f' % (errnum/float(mtest)))


def dataplot(datamat,labels):
    choice = [[0,1],[0,2],[1,2]]
    x01 = [];y01 = [];x02 = [];y02 = [];x03 = [];y03 = []
    for item in choice:
        for i in range(0,1000):
            if labels[i] == 1:
                x01.append(datamat[i][item[0]])
                y01.append(datamat[i][item[1]])
            elif labels[i] == 2:
                x02.append(datamat[i][item[0]])
                y02.append(datamat[i][item[1]])
            else:
                x03.append(datamat[i][item[0]])
                y03.append(datamat[i][item[1]])
        if item[0]+item[1] == 1:
            part = 131;xlb = 'flyMiles';ylb = 'gamePercentTats'
        elif item[0]+item[1] == 2:
            part = 132;xlb = 'flyMiles';ylb = 'iceCream'
        else:
            part = 133;xlb = 'gamePercentTats';ylb = 'iceCream'
        plt.subplot(part)
        plt.scatter(x01,y01,3);plt.scatter(x02,y02,3);plt.scatter(x03,y03,3)
        plt.legend(['notAtAll','inSmallDoes','inLargeDoes'], loc = 0)
        plt.xlabel(xlb, fontsize=12); plt.ylabel(ylb, fontsize=12)
    plt.show()